/*
This file is part of MMM.

MMM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MMM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MMM.  If not, see <http://www.gnu.org/licenses/>.
*
* @package    MMM
* @author     Andre Meixner
* @copyright  2018 High Performance Humanoid Technologies (H2T), Karlsruhe, Germany
*
*/

#ifndef __MMM_SINGLEPLOTWIDGET_H_
#define __MMM_SINGLEPLOTWIDGET_H_

#include <QWidget>
#include <set>

#ifndef Q_MOC_RUN
#include "qcustomplot.h"
#include "SensorPlotFactory.h"
#endif

class ValueContainer
{
public:
    ValueContainer(const std::string &motionFileName, const std::string &motionName,
                   const std::string &sensorName, const std::string &valueName) :
        motionFileName(motionFileName),
        motionName(motionName),
        sensorName(sensorName),
        valueName(valueName),
        name(valueName),
        x1(false), x2(false), x3(false), x4(false)
    {
    }

    void setName(bool x1, bool x2, bool x3, bool x4) {
        this->x1 = x1;
        this->x2 = x2;
        this->x3 = x3;
        this->x4 = x4;
        std::string name = "";
        std::string left = " ";
        std::string right = "";
        if (x3) name = name + "[" + sensorName + "]";
        if (x4 || (!x1 && !x2 && !x3 && !x4)) {
            name = name + " " + valueName;
            left = left + "(";
            right = right + ")";
        }
        if (x2 && x1) name = name + left + motionName + ", " + motionFileName + right;
        else if (x2) name = name + left + motionName + right;
        else if (x1) name = name + left + motionFileName + right;
        this->name = name;
    }

    std::string getHeader() {
        std::string header = "";
        if (!x3) header = header + "[" + sensorName + "]";
        if (!x4) header = header + " " + valueName;
        if (!x4 && !x2) header = header + " of";
        if (!x2) header = header + " motion " + motionName;
        if (!x1) header = header + " in file '" + motionFileName + "'";
        return header;
    }

    std::string motionFileName;
    std::string motionName;
    std::string sensorName;
    std::string valueName;
    std::string name;
    bool x1;
    bool x2;
    bool x3;
    bool x4;
};

struct vc_compare {
    bool operator()(ValueContainer* l, ValueContainer* r) const {
        return (l->motionFileName < r->motionFileName) ||
               (l->motionFileName == r->motionFileName && l->motionName < r->motionName) ||
               (l->motionFileName == r->motionFileName && l->motionName == r->motionName && l->sensorName < r->sensorName) ||
               (l->motionFileName == r->motionFileName && l->motionName == r->motionName &&
                l->sensorName == r->sensorName && l->valueName < r->valueName);
    }
};

namespace Ui {
class SinglePlotWidget;
}

class SinglePlotWidget : public QWidget
{
    Q_OBJECT

public:
    explicit SinglePlotWidget(MMM::SensorPlotFactoryPtr plot, const std::string &name, QWidget *parent = 0, bool standalone = false);
    ~SinglePlotWidget();

    void addGraph(ValueContainer* vc, QVector<double> &x, const QVector<double> &y, const std::string &name);

    void update(std::string motionFilePath, MMM::MotionList motions);

    MMM::SensorPlotFactoryPtr getPlotFactory();

    void moveSlider(float timestep);

signals:
    void showMessage(const std::string &message);
    void openMotions(MMM::MotionList motions);
    void jumpTo(float timestep);

private slots:
    void selectionChanged();
    void motionChanged();
    void addPlot();
    void savePlot();
    void titleDoubleClick(QMouseEvent* event);
    void axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part);
    void legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item);
    void mousePress(QMouseEvent* event);
    void mouseMove(QMouseEvent* event);
    void mouseRelease(QMouseEvent* event);
    void mouseWheel();
    void removeSelectedGraph();
    void removeAllGraphs();
    void contextMenuRequest(QPoint pos);
    void moveLegend();
    void graphClicked(QCPAbstractPlottable *plottable, int dataIndex);
    void changeMotionTimestep(double timestep);
    void updateMotionDeltaVis(std::vector<QCPGraph*> graphs, double delta);
    void openSelectedGraphMotion();
    void openPlottedMotions();
    void jumpToTimestep();

private:
    void checkDifferencesToPlotted(ValueContainer* vc);
    void updateText();

    Ui::SinglePlotWidget* ui;
    MMM::SensorPlotFactoryPtr plot;
    QCustomPlot* customPlot;
    std::map<std::string, std::map<std::string, MMM::MotionPtr> > motions;
    MMM::MotionPtr currentMotion;
    std::string currentMotionFileName;
    std::set<ValueContainer*, vc_compare> plotted;
    QCPTextElement* legendTitle;
    std::vector<std::tuple<ValueContainer*, QCPGraph*> > graph;
    std::vector<std::tuple<std::string, std::string> > values;
    std::string name;
    bool standalone;
    std::vector<QCPGraph*> dragGraphs;
    double mousePosX;
    std::map<std::string, double> motionTimestepDelta;
    std::string dragMotionFileName;
    QCPItemLine* slider;
    bool dragSlider;

};

#endif // SINGLEPLOTWIDGET_H
